using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;

using DirectShowLib;

public class M2Mkv : Form
{
    private Button button1;
    private RadioButton MkvRadioButton;
    private RadioButton WmvRadioButton;
    private GroupBox groupBox1;
    private Label label1;

    private Container components = null;

    // The main com object
    FilterGraph fg = null;
    // The graphbuilder interface ref
    IGraphBuilder gb = null;
    // The mediacontrol interface ref
    IMediaControl mc = null;
    // The mediaevent interface ref
    IMediaEventEx me = null;

    // Matroska support filter interface
    IBaseFilter matroska_mux = null;

    // variable to store the filename and extension
    string fName, fExt;
    // one "global" hr
    int hr;

    public M2Mkv()
    {
        InitializeComponent();
    }

    protected override void Dispose( bool disposing )
    {
        if( disposing )
        {
            if (components != null) 
            {
                components.Dispose();
            }
        }
        base.Dispose( disposing );
    }

		#region Windows Form Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.button1 = new System.Windows.Forms.Button();
        this.label1 = new System.Windows.Forms.Label();
        this.MkvRadioButton = new System.Windows.Forms.RadioButton();
        this.WmvRadioButton = new System.Windows.Forms.RadioButton();
        this.groupBox1 = new System.Windows.Forms.GroupBox();
        this.groupBox1.SuspendLayout();
        this.SuspendLayout();
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(16, 16);
        this.button1.Name = "button1";
        this.button1.TabIndex = 0;
        this.button1.Text = "Convert";
        this.button1.Click += new System.EventHandler(this.button1_Click);
        // 
        // label1
        // 
        this.label1.Location = new System.Drawing.Point(24, 120);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(80, 24);
        this.label1.TabIndex = 1;
        // 
        // MkvRadioButton
        // 
        this.MkvRadioButton.Checked = true;
        this.MkvRadioButton.Location = new System.Drawing.Point(8, 16);
        this.MkvRadioButton.Name = "MkvRadioButton";
        this.MkvRadioButton.TabIndex = 2;
        this.MkvRadioButton.TabStop = true;
        this.MkvRadioButton.Text = "Convert to mkv";
        // 
        // WmvRadioButton
        // 
        this.WmvRadioButton.Location = new System.Drawing.Point(8, 40);
        this.WmvRadioButton.Name = "WmvRadioButton";
        this.WmvRadioButton.TabIndex = 3;
        this.WmvRadioButton.TabStop = true;
        this.WmvRadioButton.Text = "Convert to wmv";
        // 
        // groupBox1
        // 
        this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                this.WmvRadioButton,
                                                                                this.MkvRadioButton});
        this.groupBox1.Location = new System.Drawing.Point(16, 40);
        this.groupBox1.Name = "groupBox1";
        this.groupBox1.Size = new System.Drawing.Size(128, 72);
        this.groupBox1.TabIndex = 4;
        this.groupBox1.TabStop = false;
        // 
        // M2Mkv
        // 
        this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
        this.ClientSize = new System.Drawing.Size(232, 150);
        this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                      this.label1,
                                                                      this.button1,
                                                                      this.groupBox1});
        this.MaximizeBox = false;
        this.Name = "M2Mkv";
        this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
        this.Text = "m2mkv";
        this.groupBox1.ResumeLayout(false);
        this.ResumeLayout(false);

    }
		#endregion

    [STAThread]
    static void Main() 
    {
        Application.Run(new M2Mkv());
    }

    //
    // method to ask the user the filename
    //
    private void button1_Click(object sender, System.EventArgs e)
    {
        OpenFileDialog ofd = new OpenFileDialog();
        if( ofd.ShowDialog() == DialogResult.OK ) 
        {
            FileInfo fi = new FileInfo( ofd.FileName );
            fExt = fi.Extension;
            fName = fi.FullName.Substring( 0, fi.FullName.Length - fExt.Length );
            CloseInterfaces();
            InitInterfaces();
            if( MkvRadioButton.Checked )
              Convert2Mkv( fName );
            else
              Convert2Wmv( fName );
        }
    }

    // 
    // This method create the filter graph
    //
    void InitInterfaces() 
    {
        try 
        {   
            fg = new FilterGraph();
            gb = (IGraphBuilder)fg;  
            mc = (IMediaControl)fg;
            me = (IMediaEventEx)fg;                
        }
        catch(Exception) 
        {
            MessageBox.Show( "Couldn't start" );
        }
    }  

    //
    //This method stop the filter graph and ensures that we stop
    //sending messages to our window
    //
    void CloseInterfaces() 
    {   
        if( me != null ) 
        {
            hr = mc.Stop();
            DsError.ThrowExceptionForHR( hr );
            
            hr = me.SetNotifyWindow( IntPtr.Zero , WM_GRAPHNOTIFY, IntPtr.Zero ); 
            DsError.ThrowExceptionForHR( hr );
        }  
        mc = null;
        me = null;
        gb = null;
        if( matroska_mux != null )
          Marshal.ReleaseComObject( matroska_mux );
        matroska_mux = null;
        if( fg != null ) 
            Marshal.ReleaseComObject( fg );
        fg = null;
    }   


    //
    // This method convert the input file to an mkv file
    //
    void Convert2Mkv( string fileName ) 
    {
        try 
        {
            label1.Text = "processing";
            button1.Enabled = false;

            hr = me.SetNotifyWindow( this.Handle , WM_GRAPHNOTIFY, IntPtr.Zero );
            DsError.ThrowExceptionForHR( hr );

            // we want to add a filewriter filter to the filter graph
            FileWriter file_writer = new FileWriter();

            // make sure we access the IFileSinkFilter interface to
            // set the file name
            IFileSinkFilter fs = (IFileSinkFilter)file_writer;
        
            fs.SetFileName( fileName + ".mkv", null );
            DsError.ThrowExceptionForHR( hr );

            // add the filter to the graph
            hr = gb.AddFilter( (IBaseFilter)file_writer, "File Writer" );
            DsError.ThrowExceptionForHR( hr );

            // create an instance of the matroska multiplex filter and add it
            // Matroska Mux Clsid = {1E1299A2-9D42-4F12-8791-D79E376F4143}	
            Guid guid = new Guid( "1E1299A2-9D42-4F12-8791-D79E376F4143" );
            Type comtype = Type.GetTypeFromCLSID( guid );
            matroska_mux = (IBaseFilter)Activator.CreateInstance( comtype );
        
            hr = gb.AddFilter( (IBaseFilter)matroska_mux, "Matroska Muxer" );
            DsError.ThrowExceptionForHR( hr );

            // use Intelligent connect to build the rest of the graph
            hr = gb.RenderFile( fileName + fExt, null );
            DsError.ThrowExceptionForHR( hr );

            // we are ready to convert
            hr = mc.Run();          
            DsError.ThrowExceptionForHR( hr );
        }
        catch( Exception ex ) 
        {
            MessageBox.Show( "Error converting to mvk: " + ex.Message );
        }
    }

    //
    // This method convert the input file to an wmv file
    //
    void Convert2Wmv( string fileName ) 
    {
        try 
        {
            label1.Text = "processing";
            button1.Enabled = false;

            hr = me.SetNotifyWindow( this.Handle , WM_GRAPHNOTIFY, IntPtr.Zero );
            DsError.ThrowExceptionForHR( hr );

            // here we use the asf writer to create wmv files
            WMAsfWriter asf_filter = new WMAsfWriter();
            IFileSinkFilter fs = (IFileSinkFilter)asf_filter;
        
            hr = fs.SetFileName( fileName + ".wmv", null );
            DsError.ThrowExceptionForHR( hr );

            hr = gb.AddFilter( (IBaseFilter)asf_filter, "WM Asf Writer" );
            DsError.ThrowExceptionForHR( hr );
        
            hr = gb.RenderFile( fileName + fExt, null );
            DsError.ThrowExceptionForHR( hr );

            hr = mc.Run();          
            DsError.ThrowExceptionForHR( hr );
        }
        catch( Exception ex ) 
        {
            MessageBox.Show( "Error converting to wmv: " + ex.Message );
        }        
    }


    int WM_GRAPHNOTIFY	= 0x00008001;

    protected override void WndProc( ref Message m )
    {
        if( m.Msg == WM_GRAPHNOTIFY )
        {
            int p1, p2;
            EventCode code;

            if( me == null )
                return;
            while( me.GetEvent( out code, out p1, out p2, 0 ) == 0 ) 
            {                                                 
                if( code == EventCode.Complete ) 
                {                        
                    label1.Text = "done";
                    button1.Enabled = true;
                    mc.Stop();
                }
                                 
                me.FreeEventParams( code, p1, p2 );                                 
             }
            return;
        }
        base.WndProc( ref m );
    }
}